<template>
  <div ref="wrapperRef" class="tui-code-wrapper" :class="{ 'tui-code-inline': props.inline }">
    <pre class="tui-code-pre"><code ref="codeBlock" :class="`language-${computedLang}`" v-text="displayContent"></code></pre>
    <!-- 语言标签 -->
    <div class="tui-code-lang">{{ computedLang }}</div>
    <!-- 复制按钮，当copy属性不为false时显示 -->
    <tui-button v-if="props.copy !== false" @click="copyCode" class="tui-code-copy-btn" size="small" radius="small">
      <tui-icon icon="tui:copy"></tui-icon>
      <span class="copy-text" v-if="isCopied">已复制!</span>
    </tui-button>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted, watch, computed, useSlots } from 'vue';
import hljs from 'highlight.js';
import type { TuiCodeProps } from './types';

const props = withDefaults(defineProps<TuiCodeProps>(), {
  code: undefined,
  lang: 'html',
  language: 'html',
  content: '',
  inline: true,
  copy: true,
});

// 定义事件
const emit = defineEmits<{
  (e: 'copy-success', copiedText: string): void;
  (e: 'copy-error', error: Error): void;
}>();

// 检查是否有默认插槽内容
const hasDefaultSlot = computed(() => {
  const slots = useSlots();
  return !!slots.default;
});

// 获取全局slots实例
const slots = useSlots();

// 计算属性获取插槽内容文本
const getSlotTextContent = (): string => {
  if (!hasDefaultSlot.value) return '';

  const slotNodes = slots.default?.();
  if (!slotNodes || slotNodes.length === 0) return '';

  // 处理插槽节点，提取文本内容
  let text = '';
  slotNodes.forEach(node => {
    if (typeof node.children === 'string') {
      text += node.children;
    } else if (Array.isArray(node.children)) {
      // 递归处理子节点
      node.children.forEach(child => {
        if (typeof child === 'string') {
          text += child;
        }
      });
    }
  });

  return text.trim();
};

// 计算属性获取内容（统一处理插槽和属性）
const displayContent = computed(() => {
  // 按照优先级获取内容
  // 1. 优先从默认插槽获取
  if (hasDefaultSlot.value) {
    return getSlotTextContent();
  }
  // 2. 其次从code.content获取
  if (props.code?.content) {
    return props.code.content.toString().trim();
  }
  // 3. 最后从content属性获取
  if (props.content) {
    return props.content.toString().trim();
  }
  // 默认返回空字符串
  return '';
});

// 复制状态
const isCopied = ref(false);
// 代码块DOM引用
const codeBlock = ref<HTMLElement | null>(null);
// 组件根元素引用
const wrapperRef = ref<HTMLElement | null>(null);

// 计算属性获取语言
const computedLang = computed(() => {
  // 优先从code对象获取lang
  if (props.code?.lang) {
    return props.code.lang;
  }
  // 其次从code对象获取language
  if (props.code?.language) {
    return props.code.language;
  }
  // 再次从lang属性获取
  if (props.lang) {
    return props.lang;
  }
  // 最后从language属性获取
  if (props.language) {
    return props.language;
  }
  // 默认返回html
  return 'html';
});

// 复制代码功能
function copyCode() {
  // 根据copy属性决定要复制的内容
  let textToCopy = '';

  if (typeof props.copy === 'string') {
    // 如果copy是字符串，则复制该字符串
    textToCopy = props.copy;
  } else if (props.copy === true) {
    // 如果copy是true，则复制当前逻辑的内容
    textToCopy = displayContent.value;
  }

  if (textToCopy) {
    navigator.clipboard.writeText(textToCopy).then(() => {
      isCopied.value = true;

      // 触发复制成功事件
      emit('copy-success', textToCopy);

      // 2秒后重置复制状态
      setTimeout(() => {
        isCopied.value = false;
      }, 2000);
    }).catch(err => {
      console.error('复制失败: ', err);
      // 触发复制失败事件
      emit('copy-error', err);
    });
  }
};

// 代码高亮处理
const highlightCode = () => {
  if (codeBlock.value && !codeBlock.value.hasAttribute('data-highlighted')) {
    // 临时禁用控制台警告输出
    const originalConsole = console.warn;

    try {
      console.warn = () => { };
      hljs.highlightElement(codeBlock.value as HTMLElement);
      codeBlock.value.setAttribute('data-highlighted', 'true');
    } finally {
      console.warn = originalConsole;
    }
  }
};

// 监听代码变化
watch(() => [props.code, props.lang, props.language, props.content, displayContent.value], () => {
  // 移除高亮标记，以便重新高亮
  if (codeBlock.value) {
    codeBlock.value.removeAttribute('data-highlighted');
  }
  // 重新高亮
  setTimeout(highlightCode, 0);
}, { deep: true });

// 设置父元素样式的函数
const setParentElementStyle = (inlineMode: boolean) => {
  if (!wrapperRef.value || !wrapperRef.value.parentElement) return;

  const parentElement = wrapperRef.value.parentElement;

  if (inlineMode) {
    // 添加flex布局样式
    parentElement.style.display = 'flex';
    parentElement.style.alignItems = 'center';
  } else {
    // 移除flex布局样式
    parentElement.style.display = '';
    parentElement.style.alignItems = '';
  }
};

// 组件挂载时高亮代码和处理父元素样式
onMounted(() => {
  highlightCode();
  // 设置父元素样式
  setParentElementStyle(props.inline);
});

// 监听inline属性变化
watch(() => props.inline, (newInline) => {
  setParentElementStyle(newInline);
});
</script>

<style scoped lang="scss">
.tui-code-wrapper {
  position: relative;
  // margin-bottom: var(--tui-spacing-medium);
  border-top: 1px solid var(--tui-color-border);

  &:last-child {
    margin-bottom: 0;
  }

  // 语言标签样式
  .tui-code-lang {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 12px;
    font-weight: var(--tui-font-weight-medium);
    color: var(--tui-color-white);
    background-color: var(--tui-color-primary);
    padding: 3px 8px;
    border-radius: 0 4px 0 4px;
    pointer-events: none;
    z-index: 10;
  }

  // 复制按钮样式
  .tui-code-copy-btn {
    position: absolute;
    top: var(--tui-spacing-large);
    right: 0;
    display: flex;
    align-items: center;
    border: none;
    cursor: pointer;
    transition: var(--tui-transition-all);
    z-index: 10;
    background: transparent;
    color: var(--tui-color-text-secondary);
    padding: 4px 8px;
    border-radius: 4px;

    &:hover,
    &:focus {
      background-color: rgba(0, 0, 0, 0.05);
      color: var(--tui-text-color-secondary);
    }

    .copy-text {
      position: absolute;
      right: 100%;
      top: 50%;
      transform: translateY(-50%);
      font-size: 12px;
      color: var(--tui-color-primary);
      font-weight: var(--tui-font-weight-medium);
      white-space: nowrap;
    }
  }

  // 代码块样式
  .tui-code-pre {
    margin: 0;
    padding: var(--tui-spacing-medium);
    background-color: var(--tui-bg-color);
    font-size: 14px;
    line-height: 1.5;

    code {
      background-color: var(--tui-color-white);
      box-shadow: var(--tui-crystal-shadow);
      transform: var(--tui-crystal-transform);
      border: 1px solid var(--tui-color-border);
      border-radius: var(--tui-border-radius-base);
      font-family: var(--tui-font-family-mono);
      font-size: 14px;
      line-height: 1.5;
      padding: var(--tui-spacing-small);
      white-space: pre;
      display: block;
      overflow-x: auto;
      transition: box-shadow 0.3s ease, transform 0.2s ease;
    }

    /* 鼠标悬停时增强水晶效果 */
    code:hover {
      box-shadow: var(--tui-crystal-shadow-hover);
      transform: var(--tui-crystal-transform-hover);
    }
  }

  // 内联代码样式
  &.tui-code-inline {
    display: inline-block;

    .tui-code-pre {
      padding: 0;
      background: none;
    }

    .tui-code-lang {
      line-height: 1.2;
      padding: 0;
      right: unset;
      right: 0;
      font-size: 10px;
    }

    .tui-code-copy-btn {
      padding: 0;
      right: unset;
      right: 0;
    }
  }
}
</style>

<!-- highlight.js 主题样式 - 必须是非scoped的才能生效 -->
<style lang="scss">
.tui-code-wrapper pre code {

  // 注释和引用
  .hljs-comment,
  .hljs-quote {
    color: #5c6370;
    font-style: italic;
  }

  // 标签、关键字和公式
  .hljs-doctag,
  .hljs-keyword,
  .hljs-formula {
    color: #c678dd;
  }

  // 章节、名称、选择器标签等
  .hljs-section,
  .hljs-name,
  .hljs-selector-tag,
  .hljs-deletion,
  .hljs-subst {
    color: #e06c75;
  }

  // 字面量
  .hljs-literal {
    color: #56b6c2;
  }

  // 字符串和相关元素
  .hljs-string,
  .hljs-regexp,
  .hljs-addition,
  .hljs-attribute {
    color: #98c379;
  }

  // 元数据中的字符串
  .hljs-meta {
    .hljs-string {
      color: #98c379;
    }
  }

  // 属性、变量和数字等
  .hljs-attr,
  .hljs-variable,
  .hljs-template-variable,
  .hljs-type,
  .hljs-selector-class,
  .hljs-selector-attr,
  .hljs-selector-pseudo,
  .hljs-number {
    color: #d19a66;
  }

  // 符号、标题等
  .hljs-symbol,
  .hljs-bullet,
  .hljs-link,
  .hljs-meta,
  .hljs-selector-id,
  .hljs-title {
    color: #61afef;
  }

  // 内置和类标题
  .hljs-built_in,
  .hljs-title.class_ {
    color: #e6c07b;
  }

  // 强调元素
  .hljs-emphasis {
    font-style: italic;
  }

  .hljs-strong {
    font-weight: bold;
  }

  // 链接样式
  .hljs-link {
    text-decoration: underline;
  }
}
</style>